#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   uart.py
@Time    :   2021/01/13 13:54:32
@Author  :   Jim 
@Version :   1.0
@Contact :   jim@yi-win.com
@License :   (C)Copyright 2017-2018, 奕枫仪器
@Desc    :   None
'''

# here put the import lib


import serial
from threading import Thread, Lock
import time
import struct
from dataConvert import DataConvert
#from serial.serialutil import *

class Uart(object):
   
    def __init__(self, Port="COM3", BaudRate="9600" ,ByteSize="8", 
            Parity="N",Stopbits="1", Timeout = 0.2,
            sendCommand="0103000000044409",
            rcvConfig="RTU;Int2_1;CRC16;0.2;4;6;22;0.01"):
        #A30313033303030303030304146320D0A
        #01030000000AC5CD
        self.port        = Port
        self.baudrate    = BaudRate
        self.bytesize    = int(ByteSize)
        self.parity      = Parity
        self.stopbits    = int(Stopbits)
        self.timeout     = Timeout
        self.sendCommand = sendCommand
        self.rcvConfig   = rcvConfig 

        #print( "self.rcvConfig: %s" % self.rcvConfig)

        self.rcv_data    = ""
        self.string_data = ""
        self._serial     = ""
        self.err = 0

    def connect(self, timeout=2):
        '''
        连接设备
        '''
        self._serial = serial.Serial()
        self._serial.port = self.port
        self._serial.baudrate = self.baudrate
        self._serial.bytesize = int(self.bytesize)
        self._serial.parity = self.parity
        self._serial.stopbits = int(self.stopbits)

        try:
            self._serial.open()
            if self._serial.isOpen():
                self._is_connected = True
        except Exception as e:
            self._is_connected = False
            self.err = -1

    def disconnect(self):
        '''
        断开连接
        '''
        if self._serial:
            self._serial.close()

        #self.start_recv_thread(datatype)#启动线程

    def write(self, data, isHex=False):
        '''
        发送数据给串口设备
        '''
        if self._is_connected:
            if isHex:
                # True "010300000044409"
                data = bytes.fromhex(data)
                #print(data)
                #print(bytes(data))
                self._serial.write(bytes(data))
            else :
                self._serial.write(bytes(data,encoding='utf8'))

    def uart_recv_thread(self,func):
        
            # self._serial= serial.Serial(self.port, self.baudrate, self.bytesize, self.parity, self.stopbits)
            # self._serial.write(  bytes.fromhex(self.sendCommand) )
            rcvC = self.rcvConfig.split(';')
            print ('rcvConfig %s' %self.rcvConfig)
            print (  rcvC )
            print( self.port+'-'+self.baudrate+'-'+str(self.bytesize)+'-'+self.parity+'-'+str(self.stopbits)+'-' )
            self.connect()

            rcv_data_hex = ''
            # if rcvC[0] == 'ASCII' :
            #     print ("RTU")
                
            if (self._is_connected == True and rcvC[0] == 'RTU') :
                print("rtu commanf %s" %rcvC[0])
                self.write (self.sendCommand,True)
                print (   self._is_connected )
                ulock = Lock()
                ulock.acquire()  
                #一定要等待0.1秒才能接受信号
                time.sleep(self.timeout)
                #这是一个字节一个字节接受的模式
                
                if self._serial.in_waiting:
                    for _ in range(self._serial.in_waiting):
                        data1 = self._serial.read(1).hex().upper()
                        #print(data1)
                        rcv_data_hex+=data1

                ulock.release()
                if self.crcCheck(rcv_data_hex) == False:
                    rcv_data_hex = ''
                else :
                    print('通过crc校验')
                    pass

            if (self._is_connected == True) and (rcvC[0] == 'ASCII') :
                # 阻塞式ASCII
                # 000319-Rx:3A 30 31 30 33 30 30 30 30 30 30 30 41 46 32 0D 0A
                # 以上命令对应ASCII :01030000000AF2
                # self._serial.write (b':01030000000AF2\r\n\r')
                # self.write (b':01030000000AF2\r\n')
                #000320-Tx:3A 30 31 30 33 31 34 34 32 38 32 33 33 33 33 34 31 44 33 33 33 33 33 34 31 43 43 43 43 43 44 34 31 44 45 36 36 36 36 34 32 36 31 39 39 39 41 44 44 0D 0A
                print ( "ascii" )
                self.write (self.sendCommand,False)
                data1 = self._serial.readline().decode() 
                print(   data1)
                if '\r' in data1 :
                    data1.replace ('\r', '')
                if '\n' in data1 :
                    data1.replace ('\n', '')
                if len(data1) > 0:
                    rcv_data_hex = str(data1)
                print( "=======" +rcv_data_hex )
                print(" 后补 ：接受和校验  : 0D0A")

            if (self._is_connected == True and rcvC[0] == 'HEX' ) :
                print ( "hex" )
                # 非RTU协议十六机制
                self.write (rcvC[-1],True)
                ulock = Lock()
                ulock.acquire()  
                #一定要等待0.1秒才能接受信号
                time.sleep(self.timeout)
                #这是一个字节一个字节接受的模式
                
                if self._serial.in_waiting:
                    for _ in range(self._serial.in_waiting):
                        data1 = self._serial.read(1).hex().upper()
                        #print(data1)
                        rcv_data_hex+=data1

                ulock.release()
                # if self.crcCheck(rcv_data_hex) == False:
                #     rcv_data_hex = ''
                # else :
                #     print('通过crc校验')
                #     pass
                print( "=======" +rcv_data_hex )

            if (self._is_connected == True and rcvC[0] == 'ASCII2') :

                print ("ascii2")
                data1 = self._serial.readline().decode() 
                print(   data1)
                if '\r' in data1 :
                    data1.replace ('\r', '')
                if '\n' in data1 :
                    data1.replace ('\n', '')
                if len(data1) > 0:
                    rcv_data_hex = str(data1)
                print( "=======" +rcv_data_hex )

            if (self._is_connected == True and rcvC[0] == 'HEX2') :
                # 非阻塞型ASCII
                print ( "hex2" )
                ulock = Lock()
                ulock.acquire()  
                #一定要等待0.1秒才能接受信号
                time.sleep(self.timeout)                
                if self._serial.in_waiting:
                    for _ in range(self._serial.in_waiting):
                        data1 = self._serial.read(1).hex()
                        #print(data1)
                        rcv_data_hex+=data1
                ulock.release()

            #self.disconnect()
            # print(recv_data_hex)
            # self.response.append(recv_data_hex)
            data = rcv_data_hex
            print(data)
            self.processData (func,data) 
            self._serial.close()
            print('data received : '+rcv_data_hex) 


    def processData(self,func,data):
        """
        根据类型处理数据
        """
        # print(self.rcvConfig[6])
        # data1 = data[int(self.rcvConfig[5]) : int(self.rcvConfig[6])]
        data3 = ''
        rcv = self.rcvConfig.split(';')
        print( data )
        if rcv[1] == "floatABCD" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            #print ("floatABCD : %s" %data1)
            if len(data1) > 0 and len(data1)%8 == 0 :
                for i in range( int(rcv[4]) ) :
                    data2 = str(data1[0:8])
                    #data2 =list(data2)
                    print(bytes.fromhex(data2))
                    data2 = struct.unpack('>f', bytes().fromhex(data2))[0]
                    data1 = data1[8:]
                    data3 = data3+str(round(data2,int(rcv[7]) ))+';'
            #print ("floatABCD : %s" %data3)


        elif rcv[1] == "floatDCBA" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            if len(data1)%8 == 0 :
                for i in range( int(rcv[4]) ) :
                    data2 = str(data1[0:8])
                    #data2 =list(data2)
                    #print(bytes.fromhex(data2))
                    data2 = struct.unpack('<f', bytes().fromhex(data2))[0]
                    data1 = data1[8:]
                    data3 = data3+str(round(data2,int(rcv[7]) ))+';'

        elif  rcv[1] == "floatBADC" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            if len(data1)%8 == 0 :
                for i in range( int(rcv[4]) ) :
                    data2 = str(data1[4:8])+str(data1[0:4])
                    #data2 =list(data2)
                    #print(bytes.fromhex(data2))
                    data2 = struct.unpack('<f', bytes().fromhex(data2))[0]
                    data1 = data1[8:]
                    data3 = data3+str(round(data2,int(rcv[7]) ))+';'

        elif  rcv[1] == "floatCDAB" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            if len(data1)%8 == 0 :
                for i in range( int(rcv[4]) ) :
                    data2 = str(data1[4:8])+str(data1[0:4])
                    #data2 =list(data2)
                    #print(bytes.fromhex(data2))
                    data2 = struct.unpack('>f', bytes().fromhex(data2))[0]
                    data1 = data1[8:]
                    data3 = data3+str(round(data2,int(rcv[7]) ))+';'

        elif  rcv[1] == "HEX_ASCII" :
            print('hex ascii')
            data1 = data[int(rcv[5]) : int(rcv[6])]
            print (data1)
            data3 =''
            if len(data1) > 0 :
                data3 = bytearray.fromhex(data1).decode().strip(' ')+';'
            print (data3)

        elif rcv[1] == "Int2_1" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            if len(data1)%4 == 0 :
                for i in range( int(rcv[4]) ) : 
                    data2 = str(data1[0:4])
                    data2 = struct.unpack('>h', bytes().fromhex(data2))[0]
                    data2 = data2*float(rcv[7])
                    data1 = data1[4:]
                    data3 = data3+str(data2)+';'
             
        elif rcv[1] == "Int2_2" :
            data1 = data[int(rcv[5]) : int(rcv[6])]
            if len(data1)%4 == 0 :
                for i in range( int(rcv[4]) ) : 
                    data2 = str(data1[0:4])
                    data2 = struct.unpack('<h', bytes().fromhex(data2))[0]
                    data2 = data2*float(rcv[7])
                    data1 = data1[4:]
                    data3 = data3+str(data2)+';'
    
        elif rcv[1] == "ASCII" :
            if len(data) > 0:
                if (';' in data):
                    data = data.split(';')
                    if len(data) >= int(rcv[4]):
                        data = data[int(rcv[5]) : int(rcv[6])]
                        for value in data:
                            data3+=value.strip()+';'

                elif (',' in data):
                    data = data.split(',')

                    if len(data) >= int(rcv[4]):
                        data = data[int(rcv[5]) : int(rcv[6])]
                        for value in data:
                            data3+=value.strip()+';'

                else  :

                    data = data.split(' ')
                    while '' in data:
                        data.remove('')
                    print (  data ) 
                    if len(data) >= int(rcv[4]):
                        data = data[int(rcv[5]) : int(rcv[6])]
                        for value in data:
                            data3+=value+';'

        if data3 == '' :
            print (" rcv %s组数据  "   %rcv[4] )
            for i in range(  int(rcv[4])  ) : 
                data3 = data3+'0;'  
   
        if len(data3.split(';')) -1 != int(rcv[4]) :
            for i in range(  int(rcv[4])  ) : 
                data3 = data3+'0;'
        print( data3.split(';') )

        func ( data3 )   


    def start_recv_thread(self,func):
        thread = Thread( target=self.uart_recv_thread,args=(func, ) )#把接收到的数据用线程分配到CPU里去
        thread.setDaemon(True)
        thread.start()
        thread.join()#线程完成才到下一个

    def hex2int(self, data):
        """
        docstring
        """
        return int( data, 16 )

    def crc16(self,string):
        '''
        一般发送命令都是'01030000000A'这样的字符串
        输入：test2 = '01030000000A'
        输出：0xc5cd
        hexstr[2:].upper()  去掉
        '''
        data = bytearray.fromhex(string)
        crc = 0xFFFF
        for pos in data:
            crc ^= pos
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1       
        return hex(((crc & 0xff) << 8) + (crc >> 8))[2:].upper()

    def crcCheck(self,string):
        ''' 
        @@@不接受字节流数据@@@@@@ test3 = b'\x01\x03\x00\x00\x00\x0A\xC5\xCD' 
        确认输入的是 类似格式test1 = '01030000000AC5CD'
        去掉一个串的后四位 string[:-4]
        crc运算结果与后四位比较 string[-4:]
        '''
        if len(string) > 4 :
            if self.crc16(string[:-4]) == string[-4:] :
                return True
            else:
                return False
            print(string)
        else:
            return False

    def __del__(self):
        class_name = self.__class__.__name__
        print (class_name, " class destroyed")     

def t(data):
    """
    docstring
    """
    print('test end')

if __name__ == "__main__":
    uart = Uart()
    uart.start_recv_thread(t)



            

        
    
        

